#include "Poly.h"

namespace Y{

bool ClippingPoly::deb = false;


ClippingPoly::ClippingPoly( const Vertex3f& v0,const Vertex3f& v1,const Vertex3f& v2,const Vertex3f& v3 ):
	center ( (v0 + v1 + v2 + v3) / 4.0 )
{
	l.resize(4);
	l[0](v0,v1);
	l[1](v1,v2);
	l[2](v2,v3);
	l[3](v3,v0);
}

ClippingPoly::ClippingPoly( Vertex3f *va, int s ):
	l( s )
{
	for ( int i = 0; i < size(); ++i ){
		l[i]( va[i],va[(i + 1) % size()] );
		center += va[i];
	}
	center /= (float) size();
}

ClippingPoly::ClippingPoly( const Poly& vec ):
	l ( vec.size() )
{
	for ( int i = 0; i < size(); ++i ){
		l[i]( vec[i],vec[(i + 1) % size()] );
		center += vec[i];
	}
	center /= (float) size();
}


bool ClippingPoly::sameSign ( float f, float f2 ){
	return ( (f >= 0.0 && f2 >= 0.0) || (f <= 0.0 && f2 <= 0.0) );
}

bool ClippingPoly::sameSignX ( float f, float f2 ){
	if ( fabsf(f) < 0.001 || fabsf(f2) < 0.001 ){ return false; }
	return ( (f < 0.0 && f2 < 0.0) || (f > 0.0 && f2 > 0.0) );
}


std::vector< Vertex3f > ClippingPoly::clipInclusively ( const Poly& passed ){
	std::vector <Vertex3f> tmp;
	std::vector <Vertex3f> r = passed;
	
	bool lastIn,currIn;
	int nClipLines = l.size();
	int nClipPoints = passed.size();
	
	for ( int i = 0; i < nClipLines; ++i ){
		float ccenter = l[i].compare( center );
		lastIn = sameSign ( l[i].compare( r[0] ), ccenter );

		for ( int iq = 1; iq < nClipPoints + 1; ++iq ){
			int q = iq % nClipPoints;
			currIn = sameSign ( l[i].compare( r[q] ), ccenter );
			
			if ( currIn ){
				if ( ! lastIn ){
					tmp.push_back( Line::intersection( Line(r[q],r[iq - 1]) , l[i] ) );
				}
				tmp.push_back( r[q] );
			}
			else{
				if ( lastIn ){
					tmp.push_back( Line::intersection( Line(r[q],r[iq - 1]) , l[i] ) );
				}
			}
			
			lastIn = currIn;
		}
		
		r = tmp;
		nClipPoints = r.size();
		tmp.clear();
	}
	return r;
}


void ClippingPoly::clipExclusively ( const Poly& passed, std::vector < Poly >& ret ){
	
	int nClipLines = size();
	int nClipPoints = passed.size();

	Line checkLines[nClipPoints];
	Vertex3f checkCenter;
	for ( int i = 0; i < nClipPoints; ++i ){
		checkLines[i] = Line( passed[i], passed[(i + 1) % nClipPoints] );
		checkCenter += passed[i];
	}
	checkCenter /= (float) nClipPoints;
	
	{
		bool discardTest = true;
		for ( int i = 0; i < size(); ++i ){
			bool allIn = true;
			for ( int j = 0; j < nClipPoints; ++j ){
				if ( ! sameSignX( checkLines[j].compare( l[i].p[0] ), checkLines[j].compare( checkCenter ) ) ){ allIn = false;break; }
			}
			if ( allIn ){ discardTest = false;break; }
		}
		
		if ( discardTest ){ ret.push_back( passed );return; }
	}
	
	std::vector <Vertex3f> tmp;
	std::vector <Vertex3f> nr;
	
	std::vector <Vertex3f> r = passed;
	bool lastIn,currIn;
	
	for ( int i = 0; i < nClipLines; ++i ){
		float ccenter = l[i].compare( center );
		lastIn = sameSign ( l[i].compare( r[0] ), ccenter );
		
		int nOut = 0;
		for ( int iq = 1, q = 1; iq < nClipPoints + 1; ++iq, ++q ){
			if ( q == nClipPoints ){ q = 0; }
			currIn = sameSign ( l[i].compare( r[q] ), ccenter );

			if ( currIn ){
				if ( !lastIn ){
					tmp.push_back( Line::intersection( r[q],r[iq - 1] , l[i] ) );
					nr.push_back( tmp.back() );
				}
				nr.push_back( r[q] );
			}
			else{
				nOut++;
				if ( lastIn ){ 
					tmp.push_back( Line::intersection( r[q],r[iq - 1] , l[i] ) );
					nr.push_back( tmp.back() );
				}
				tmp.push_back( r[q] );
			}
			lastIn = currIn;
		}
		
		if ( nOut > 0 ){
			ret.push_back( tmp );
		}
		
		r = nr;
		nClipPoints = r.size();
		
		tmp.clear();
		nr.clear();
	}

}

void ClippingPoly::translate (float x, float y){ 
	Vertex3f m(x,y,0.0);
	for ( int i = 0; i < size(); ++i ){
		l[i] = Line(l[i].p[0] + m, l[i].p[1] + m);
	}
	center += m;
}

void ClippingPoly::translate (const Vertex3f& v){
	for ( int i = 0; i < size(); ++i ){
		l[i] = Line(l[i].p[0] + v,l[i].p[1] + v);
	}
	center += v;
}

}